package cn.schoolwow.quickdao.module.database.dql.condition.kit;

import cn.schoolwow.quickdao.domain.DAO;
import cn.schoolwow.quickdao.domain.QuickDAOConfig;
import cn.schoolwow.quickdao.domain.database.dql.condition.Condition;
import cn.schoolwow.quickdao.domain.database.dql.condition.LambdaCondition;
import cn.schoolwow.quickdao.domain.database.dql.condition.QueryColumnTypeMapping;
import cn.schoolwow.quickdao.domain.database.dql.response.PageVo;
import cn.schoolwow.quickdao.domain.database.dql.response.Response;
import cn.schoolwow.quickdao.domain.database.dql.subCondition.SubCondition;
import cn.schoolwow.quickdao.domain.database.parent.DatabaseType;
import cn.schoolwow.quickdao.domain.entity.Entity;
import cn.schoolwow.quickdao.domain.entity.Property;
import cn.schoolwow.quickdao.domain.provider.DatabaseProvider;
import cn.schoolwow.quickdao.module.database.dql.condition.domain.QueryOption;
import cn.schoolwow.quickdao.module.database.dql.condition.domain.SQLFragmentEntry;
import cn.schoolwow.quickdao.module.database.dql.condition.flow.get.GetFromConditionStatement;
import cn.schoolwow.quickdao.module.database.dql.condition.service.CloneConditionFlow;
import cn.schoolwow.quickdao.module.database.dql.condition.service.ExecuteConditionCompositeBusiness;
import cn.schoolwow.quickdao.module.database.dql.parent.domain.QueryContext;
import cn.schoolwow.quickdao.module.database.dql.response.kit.ResponseImpl;
import cn.schoolwow.quickdao.module.database.dql.subCondition.domain.SubQueryOption;
import cn.schoolwow.quickdao.module.database.dql.subCondition.kit.SubConditionImpl;
import cn.schoolwow.quickflow.QuickFlow;
import cn.schoolwow.quickflow.domain.FlowContext;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;

public class ConditionImpl<T> implements Condition<T>, Serializable, Cloneable {
    private boolean hasExecute;

    public QueryOption queryOption = new QueryOption();

    public ConditionImpl(Entity entity, QuickFlow quickFlow, QuickDAOConfig quickDAOConfig) {
        queryOption.queryTableOption.entity = entity;
        queryOption.quickFlow = quickFlow;
        queryOption.quickDAOConfig = quickDAOConfig;
    }

    public ConditionImpl(Condition fromCondition, QuickFlow quickFlow, QuickDAOConfig quickDAOConfig) {
        queryOption.queryTableOption.fromCondition = fromCondition;
        queryOption.quickFlow = quickFlow;
        queryOption.quickDAOConfig = quickDAOConfig;
    }

    private ConditionImpl(QueryOption queryOption){
        this.queryOption = queryOption;
    }

    @Override
    public Condition<T> tableAliasName(String tableAliasName) {
        queryOption.queryTableOption.tableAliasName = tableAliasName;
        return this;
    }

    @Override
    public Condition<T> distinct() {
        queryOption.queryColumnOption.distinct = "distinct ";
        return this;
    }

    @Override
    public Condition<T> addNullQuery(String field) {
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} is null"));
        return this;
    }

    @Override
    public Condition<T> addNotNullQuery(String field) {
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} is not null"));
        return this;
    }

    @Override
    public Condition<T> addEmptyQuery(String field) {
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} is not null and {} = ''"));
        return this;
    }

    @Override
    public Condition<T> addNotEmptyQuery(String field) {
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} is not null and {} != ''"));
        return this;
    }

    @Override
    public Condition<T> addInQuery(String field, String inQuery) {
        if (null == inQuery || inQuery.isEmpty()) {
            return this;
        }
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} in (" + inQuery + ")"));
        return this;
    }

    @Override
    public Condition<T> addInQuery(String field, Object... values) {
        addInQuery(field, values, "in");
        return this;
    }

    @Override
    public Condition<T> addInQuery(String field, Collection values) {
        return addInQuery(field, values.toArray(new Object[0]));
    }

    @Override
    public Condition<T> addNotInQuery(String field, String inQuery) {
        if (null == inQuery || inQuery.isEmpty()) {
            return this;
        }
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} not in (" + inQuery + ")"));
        return this;
    }

    @Override
    public Condition<T> addNotInQuery(String field, Object... values) {
        addInQuery(field, values, "not in");
        return this;
    }

    @Override
    public Condition<T> addNotInQuery(String field, Collection values) {
        return addNotInQuery(field, values.toArray(new Object[0]));
    }

    @Override
    public Condition<T> addBetweenQuery(String field, Object start, Object end) {
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} between ? and ?"));
        queryOption.queryFragmentOption.whereParameterList.add(start);
        queryOption.queryFragmentOption.whereParameterList.add(end);
        return this;
    }

    @Override
    public Condition<T> addLikeQuery(String field, Object value) {
        if (value == null || value.toString().equals("")) {
            return this;
        }
        switch (queryOption.quickDAOConfig.databaseContext.databaseProvider.getDatabaseType()){
            case SQLServer:{
                queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "charindex(?,{}) > 0"));
                queryOption.queryFragmentOption.whereParameterList.add(value.toString());
            }break;
            default:{
                queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} like ?"));
                queryOption.queryFragmentOption.whereParameterList.add(value);
            }
        }
        return this;
    }

    @Override
    public Condition<T> addNotLikeQuery(String field, Object value) {
        if (value == null || value.toString().equals("")) {
            return this;
        }
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} not like ?"));
        queryOption.queryFragmentOption.whereParameterList.add(value);
        return this;
    }

    @Override
    public Condition<T> addQuery(String field, Object value) {
        addQuery(field, "=", value);
        return this;
    }

    @Override
    public Condition<T> addQuery(String field, String operator, Object value) {
        if (null == value) {
            addNullQuery(field);
        } else if (value.toString().isEmpty()) {
            addEmptyQuery(field);
        } else {
            Entity entity = queryOption.queryTableOption.entity;
            Property property = null==entity?null:entity.getPropertyByFieldNameOrColumnName(field);
            if(null==property){
                queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} " + operator + "?"));
            }else{
                queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} " + operator + " " + (null == property.function ? "?" : property.function)));
            }
            queryOption.queryFragmentOption.whereParameterList.add(value);
        }
        return this;
    }

    @Override
    public Condition<T> addIntervalQuery(String field, String value) {
        if(!value.contains(",")){
            return this;
        }
        Long priceStart = Long.parseLong(value.substring(1,value.indexOf(",")));
        Long priceEnd = Long.parseLong(value.substring(value.indexOf(",")+1, value.length()-1));
        if(priceEnd<priceStart){
            throw new IllegalArgumentException("开闭区间不合法!请检查!开闭区间值:"+value);
        }
        switch (value.charAt(0)){
            case '(':addQuery(field, ">", priceStart);break;
            case '[':addQuery(field, ">=", priceStart);break;
            default:{
                throw new IllegalArgumentException("开闭区间开始值必须为'('或者'['!当前值:"+value.charAt(0));
            }
        }
        switch (value.charAt(value.length()-1)){
            case ')':addQuery(field, "<", priceEnd);break;
            case ']':addQuery(field, "<=", priceEnd);break;
            default:{
                throw new IllegalArgumentException("开闭区间结束值必须为')'或者']'!当前值:"+value.charAt(value.length()-1));
            }
        }
        return this;
    }

    @Override
    public Condition<T> addJSONQuery(String field, String jsonPath, String operator, Object value) {
        if(null==operator){
            operator = "=";
        }
        String fieldQuery = "?";
        //支持in查询
        switch (operator.toLowerCase(Locale.ROOT).trim()){
            case "in":
            case "not in":{
                int length = -1;
                if(value instanceof Arrays){
                    length = Array.getLength(value);
                    for(int i=0;i<length;i++){
                        Object instance = Array.get(value,i);
                        queryOption.queryFragmentOption.whereParameterList.add(instance);
                    }
                }else if(value instanceof Collection){
                    Collection collection = (Collection)value;
                    length = collection.size();
                    queryOption.queryFragmentOption.whereParameterList.addAll(collection);
                }else{
                    throw new IllegalArgumentException("in查询的参数必须为数组或者集合");
                }
                StringBuilder fieldQueryBuilder = new StringBuilder("(");
                for (int i = 0; i < length; i++) {
                    fieldQueryBuilder.append("?,");
                }
                fieldQueryBuilder.deleteCharAt(fieldQueryBuilder.length() - 1);
                fieldQueryBuilder.append(")");
                fieldQuery = fieldQueryBuilder.toString();
            }break;
            default:{
                queryOption.queryFragmentOption.whereParameterList.add(value);
            }
        }

        DatabaseType databaseType = queryOption.quickDAOConfig.databaseContext.databaseProvider.getDatabaseType();
        switch (databaseType){
            case Mysql:{
                queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "json_extract({},'$."+jsonPath+"') "+operator+" "+fieldQuery));
            }break;
            case Postgresql:{
                queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, "{} ->> '"+jsonPath+"' "+operator+" "+fieldQuery));
            }break;
            default:{
                throw new IllegalArgumentException("暂不支持当前数据库JSON查询语法!数据库:"+databaseType.name());
            }
        }
        return this;
    }

    @Override
    public Condition<T> addCompositeQuery(String field, String value) {
        if(value.startsWith("null:")){
            addNullQuery(field);
        }else if(value.startsWith("not null:")){
            addNotNullQuery(field);
        }else if(value.startsWith("empty:")){
            addEmptyQuery(field);
        }else if(value.startsWith("not empty:")){
            addNotEmptyQuery(field);
        }else if(value.startsWith("like:")){
            addLikeQuery(field, value.substring(5));
        }else if(value.startsWith("not like:")){
            addNotLikeQuery(field, value.substring(9));
        }else if(value.startsWith("in:")){
            addInQuery(field, Arrays.asList(value.substring(3).split(",", -1)));
        }else if(value.startsWith("not in:")){
            addNotInQuery(field, value.substring(7));
        }else if(value.startsWith("interval:")){
            addIntervalQuery(field, value.substring(9));
        }else if(value.startsWith("between:")){
            String start = value.substring(8,value.indexOf(","));
            String end = value.substring(value.indexOf(",")+1);
            addBetweenQuery(field, start, end);
        }else if(value.startsWith("gt:")){
            addQuery(field, ">", value.substring(3));
        }else if(value.startsWith("gte:")){
            addQuery(field, ">=", value.substring(4));
        }else if(value.startsWith("lt:")){
            addQuery(field, "<", value.substring(3));
        }else if(value.startsWith("lte:")){
            addQuery(field, "<=", value.substring(4));
        }else{
            addQuery(field, value);
        }
        return this;
    }

    @Override
    public Condition<T> addRawQuery(String query, Object... parameterList) {
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", null, query));
        if (null != parameterList && parameterList.length > 0) {
            queryOption.queryFragmentOption.whereParameterList.addAll(Arrays.asList(parameterList));
        }
        return this;
    }

    @Override
    public Condition<T> addSubQuery(String field, Condition subQuery) {
        return addSubQuery(field, "=", subQuery);
    }

    @Override
    public Condition<T> addSubQuery(String field, String operator, Condition subCondition) {
        queryOption.setConditionTableAliasName(subCondition);
        FlowContext flowContext = queryOption.quickFlow.startFlow(new GetFromConditionStatement())
                .putTemporaryData("fromCondition", subCondition)
                .execute();
        String fromConditionStatement = (String) flowContext.checkData("fromConditionStatement");
        List<Object> fromConditionParameters = (List<Object>) flowContext.getData("fromConditionParameters");
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, " {} " + operator + " (" + fromConditionStatement + ")"));
        queryOption.queryFragmentOption.whereParameterList.addAll(fromConditionParameters);
        return this;
    }

    @Override
    public Condition<T> addExistSubQuery(Condition subQuery) {
        addExistSubQuery(subQuery, "exists");
        return this;
    }

    @Override
    public Condition<T> addNotExistSubQuery(Condition subQuery) {
        addExistSubQuery(subQuery, "not exists");
        return this;
    }

    @Override
    public Condition<T> addColumn(String... fields) {
        queryOption.queryColumnOption.columnList.addAll(Arrays.asList(fields));
        return this;
    }

    @Override
    public Condition<T> addColumnAs(String column, String columnAliasName) {
        return addColumn(column + " as " + queryOption.quickDAOConfig.databaseContext.databaseProvider.escape(columnAliasName));
    }

    @Override
    public Condition<T> addTableColumn() {
        for(Property property:queryOption.queryTableOption.entity.properties){
            if(null==property.name||property.name.isEmpty()||property.name.equalsIgnoreCase(property.column)){
                queryOption.queryColumnOption.columnList.add(property.column);
            }else {
                DatabaseProvider databaseProvider = queryOption.quickDAOConfig.databaseContext.databaseProvider;
                switch (databaseProvider.getDatabaseType()){
                    case Postgresql:{
                        queryOption.queryColumnOption.columnList.add(property.column + " " + databaseProvider.escape(property.name));
                    }break;
                    default:{
                        queryOption.queryColumnOption.columnList.add(property.column + " " + property.name);
                    }break;
                }
            }
        }
        return this;
    }

    @Override
    public Condition<T> addExcludeColumn(String... excludeFields) {
        queryOption.queryColumnOption.excludeColumnList.addAll(Arrays.asList(excludeFields));
        return this;
    }

    @Override
    public Condition<T> setColumnTypeMapping(QueryColumnTypeMapping queryColumnTypeMapping) {
        queryOption.queryColumnOption.queryColumnTypeMapping = queryColumnTypeMapping;
        return this;
    }

    @Override
    public Condition<T> setColumnTypeMap(String columnLabel, Class type) {
        queryOption.queryColumnOption.queryColumnTypeMap.put(columnLabel, type);
        return this;
    }

    @Override
    public Condition<T> addColumn(Condition subCondition) {
        FlowContext flowContext = queryOption.quickFlow.startFlow(new GetFromConditionStatement())
                .putTemporaryData("fromCondition", subCondition)
                .execute();
        String fromConditionStatement = (String) flowContext.checkData("fromConditionStatement");
        List<Object> fromConditionParameters = (List<Object>) flowContext.getData("fromConditionParameters");
        queryOption.queryColumnOption.columnList.add("("+fromConditionStatement+")");
        queryOption.queryColumnOption.columnParameterList.addAll(fromConditionParameters);
        return this;
    }

    @Override
    public Condition<T> addColumn(Condition subCondition, String columnNameAlias) {
        queryOption.setConditionTableAliasName(subCondition);
        FlowContext flowContext = queryOption.quickFlow.startFlow(new GetFromConditionStatement())
                .putTemporaryData("fromCondition", subCondition)
                .execute();
        String fromConditionStatement = (String) flowContext.checkData("fromConditionStatement");
        List<Object> fromConditionParameters = (List<Object>) flowContext.getData("fromConditionParameters");

        queryOption.queryColumnOption.columnList.add("( " + fromConditionStatement + ") " + columnNameAlias);
        queryOption.queryColumnOption.columnParameterList.addAll(fromConditionParameters);
        return this;
    }

    @Override
    public Condition<T> addUpdate(String field, Object value) {
        queryOption.queryUpdateOption.setList.add(new SQLFragmentEntry(",", field, "{} = ?"));
        queryOption.queryUpdateOption.setParameterList.add(value);
        return this;
    }

    @Override
    public Condition<T> addNullUpdate(String field) {
        queryOption.queryUpdateOption.setList.add(new SQLFragmentEntry(",", field, "{} = null"));
        return this;
    }

    @Override
    public Condition<T> addRawUpdate(String update, Object... parameterList) {
        queryOption.queryUpdateOption.setList.add(new SQLFragmentEntry(",", null, update));
        queryOption.queryUpdateOption.setParameterList.addAll(Arrays.asList(parameterList));
        return this;
    }

    @Override
    public Condition<T> or(String or, Object... parameterList) {
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("or", null, or));
        if (null != parameterList && parameterList.length > 0) {
            queryOption.queryFragmentOption.whereParameterList.addAll(Arrays.asList(parameterList));
        }
        return this;
    }

    @Override
    public Condition<T> groupBy(String... fields) {
        for(String field:fields){
            queryOption.queryFragmentOption.groupByList.add(new SQLFragmentEntry(",", field, "{}"));
        }
        return this;
    }

    @Override
    public Condition<T> having(String having, Object... parameterList) {
        queryOption.queryFragmentOption.havingList.add(new SQLFragmentEntry("and", null, having));
        if (null != parameterList && parameterList.length > 0) {
            queryOption.queryFragmentOption.havingParameterList.addAll(Arrays.asList(parameterList));
        }
        return this;
    }

    @Override
    public Condition<T> having(String field, String operator, Condition subCondition) {
        queryOption.setConditionTableAliasName(subCondition);

        FlowContext flowContext = queryOption.quickFlow.startFlow(new GetFromConditionStatement())
                .putTemporaryData("fromCondition", subCondition)
                .execute();
        String fromConditionStatement = (String) flowContext.checkData("fromConditionStatement");
        List<Object> fromConditionParameters = (List<Object>) flowContext.getData("fromConditionParameters");

        queryOption.queryFragmentOption.havingList.add(new SQLFragmentEntry("and", field, "{}" + operator + " (" + fromConditionStatement + ")"));
        queryOption.queryFragmentOption.havingParameterList.addAll(fromConditionParameters);
        return this;
    }

    @Override
    public <E> SubCondition<E, T> crossJoinTable(Class<E> clazz) {
        SubQueryOption subQueryOption = new SubQueryOption();
        subQueryOption.subQueryTableOption.entity = queryOption.quickDAOConfig.getEntityByClassName(clazz.getName());
        subQueryOption.subQueryJoinTableOption.join = "cross join";
        subQueryOption.subQueryJoinTableOption.queryOption = queryOption;
        subQueryOption.subQueryJoinTableOption.condition = this;
        queryOption.subQueryOptionList.add(subQueryOption);

        return new SubConditionImpl<>(subQueryOption);
    }

    @Override
    public SubCondition<?, T> crossJoinTable(String tableName) {
        SubQueryOption subQueryOption = new SubQueryOption();
        subQueryOption.subQueryTableOption.entity = queryOption.quickDAOConfig.getDatabaseEntityByTableName(tableName);
        if(null==subQueryOption.subQueryTableOption.entity){
            throw new IllegalArgumentException("关联表不存在!表名:" + tableName);
        }
        subQueryOption.subQueryJoinTableOption.join = "cross join";
        subQueryOption.subQueryJoinTableOption.queryOption = queryOption;
        subQueryOption.subQueryJoinTableOption.condition = this;
        queryOption.subQueryOptionList.add(subQueryOption);

        return new SubConditionImpl<>(subQueryOption);
    }

    @Override
    public <E> SubCondition<E, T> joinTable(Class<E> clazz, String primaryField, String joinTableField) {
        String compositeFieldName = null;
        if(null!=queryOption.queryTableOption.entity){
            compositeFieldName = queryOption.queryTableOption.entity.getCompositeFieldName(clazz.getName());
        }
        return joinTable(clazz, primaryField, joinTableField, compositeFieldName);
    }

    @Override
    public <E> SubCondition<E, T> joinTable(Class<E> clazz, String primaryField, String joinTableField, String compositeField) {
        SubQueryOption subQueryOption = new SubQueryOption();
        subQueryOption.subQueryTableOption.entity = queryOption.quickDAOConfig.getEntityByClassName(clazz.getName());
        subQueryOption.subQueryJoinTableOption.join = "inner join";
        if(null==queryOption.queryTableOption.entity){
            subQueryOption.subQueryJoinTableOption.primaryField = primaryField;
        }else{
            subQueryOption.subQueryJoinTableOption.primaryField = queryOption.queryTableOption.entity.getColumnNameByFieldName(primaryField);
        }
        if(null==subQueryOption.subQueryTableOption.entity){
            subQueryOption.subQueryJoinTableOption.joinTableField = joinTableField;
        }else{
            subQueryOption.subQueryJoinTableOption.joinTableField = subQueryOption.subQueryTableOption.entity.getColumnNameByFieldName(joinTableField);
        }
        subQueryOption.subQueryJoinTableOption.compositeFieldName = compositeField;
        subQueryOption.subQueryJoinTableOption.queryOption = queryOption;
        subQueryOption.subQueryJoinTableOption.condition = this;
        queryOption.subQueryOptionList.add(subQueryOption);

        return new SubConditionImpl<>(subQueryOption);
    }

    @Override
    public <E> SubCondition<E, T> joinTable(Condition<E> joinCondition, String primaryField, String joinConditionField) {
        SubQueryOption subQueryOption = new SubQueryOption();
        subQueryOption.subQueryTableOption.joinCondition = joinCondition;
        subQueryOption.subQueryJoinTableOption.join = "inner join";
        subQueryOption.subQueryJoinTableOption.primaryField = queryOption.queryTableOption.entity.getColumnNameByFieldName(primaryField);
        subQueryOption.subQueryJoinTableOption.joinTableField = joinConditionField;
        subQueryOption.subQueryJoinTableOption.queryOption = queryOption;
        subQueryOption.subQueryJoinTableOption.condition = this;
        queryOption.subQueryOptionList.add(subQueryOption);

        return new SubConditionImpl<>(subQueryOption);
    }

    @Override
    public SubCondition<?, T> joinTable(String tableName, String primaryField, String joinTableField) {
        SubQueryOption subQueryOption = new SubQueryOption();
        subQueryOption.subQueryTableOption.entity = queryOption.quickDAOConfig.getDatabaseEntityByTableName(tableName);
        if(null==subQueryOption.subQueryTableOption.entity){
            throw new IllegalArgumentException("关联表不存在!表名:" + tableName);
        }
        subQueryOption.subQueryJoinTableOption.join = "inner join";
        subQueryOption.subQueryJoinTableOption.primaryField = queryOption.queryTableOption.entity.getColumnNameByFieldName(primaryField);
        subQueryOption.subQueryJoinTableOption.joinTableField = joinTableField;
        subQueryOption.subQueryJoinTableOption.queryOption = queryOption;
        subQueryOption.subQueryJoinTableOption.condition = this;
        queryOption.subQueryOptionList.add(subQueryOption);

        return new SubConditionImpl<>(subQueryOption);
    }

    @Override
    public Condition<T> order(String field, String asc) {
        queryOption.queryFragmentOption.orderByList.add(new SQLFragmentEntry(",", field, "{} " + asc));
        return this;
    }

    @Override
    public Condition<T> orderBy(String... fields) {
        for (String field : fields) {
            queryOption.queryFragmentOption.orderByList.add(new SQLFragmentEntry(",", field, "{} asc"));
        }
        return this;
    }

    @Override
    public Condition<T> orderByDesc(String... fields) {
        for (String field : fields) {
            queryOption.queryFragmentOption.orderByList.add(new SQLFragmentEntry(",", field, "{} desc"));
        }
        return this;
    }

    @Override
    public Condition<T> orderByRaw(String orderBy) {
        queryOption.queryFragmentOption.orderByList.add(new SQLFragmentEntry(",", null, orderBy));
        return this;
    }

    @Override
    public Condition<T> limit(long offset, long limit) {
        switch (queryOption.quickDAOConfig.databaseContext.databaseProvider.getDatabaseType()){
            case Postgresql:{
                queryOption.queryPagingOption.limit = "limit " + limit + " offset " + offset;
            }break;
            case Oracle:{
                Condition fromCondition = new ConditionImpl<>(this, queryOption.quickFlow, queryOption.quickDAOConfig);
                Condition subCondition = fromCondition
                        .tableAliasName("a")
                        .addColumn("a.*", "rownum rn")
                        .addQuery("rownum", "<=", limit + offset);
                Condition condition = new ConditionImpl<>(subCondition, queryOption.quickFlow, queryOption.quickDAOConfig)
                        .tableAliasName("b")
                        .addQuery("rn", ">=", offset + 1);
                if ("JSONObject".equals(queryOption.queryTableOption.entity.clazz.getSimpleName())) {
                    condition.addColumn("b.*");
                } else {
                    for (Property property : queryOption.queryTableOption.entity.properties) {
                        condition.addColumn("b." + queryOption.queryTableOption.tableAliasName + "_" + property.column);
                    }
                    if (queryOption.queryColumnOption.compositeField) {
                        for (SubQueryOption subQueryOption : queryOption.subQueryOptionList) {
                            for (Property property : subQueryOption.subQueryTableOption.entity.properties) {
                                condition.addColumn("b." + subQueryOption.subQueryTableOption.tableAliasName + "_" + property.column);
                            }
                        }
                    }
                }
                return condition;
            }
            case SQLServer:{
                queryOption.queryPagingOption.limit = "offset " + offset + " rows fetch next " + limit + " rows only";
            }break;
            default:{
                queryOption.queryPagingOption.limit = "limit " + offset + "," + limit;
            }break;
        }
        return this;
    }

    @Override
    public Condition<T> page(int pageNum, int pageSize) {
        switch (queryOption.quickDAOConfig.databaseContext.databaseProvider.getDatabaseType()){
            case Postgresql:{
                queryOption.queryPagingOption.limit = "limit " + pageSize + " offset " + (pageNum - 1) * pageSize;
            }break;
            case Oracle:{
                ConditionImpl condition = (ConditionImpl) limit((pageNum - 1) * pageSize, pageSize);
                condition.queryOption.queryPagingOption.pageVo = new PageVo<>();
                condition.queryOption.queryPagingOption.pageVo.setPageSize(pageSize);
                condition.queryOption.queryPagingOption.pageVo.setCurrentPage(pageNum);
                return condition;
            }
            case SQLServer:{
                queryOption.queryPagingOption.limit = "offset " + (pageNum - 1) * pageSize + " rows " + " fetch next " + pageSize + " rows only";
            }break;
            default:{
                queryOption.queryPagingOption.limit = "limit " + (pageNum - 1) * pageSize + "," + pageSize;
            }break;
        }
        queryOption.queryPagingOption.pageVo.setPageSize(pageSize);
        queryOption.queryPagingOption.pageVo.setCurrentPage(pageNum);
        return this;
    }

    @Override
    public Condition<T> compositeField() {
        queryOption.queryColumnOption.compositeField = true;
        return this;
    }

    @Override
    public LambdaCondition<T> lambdaCondition() {
        LambdaConditionInvocationHandler<T> invocationHandler = new LambdaConditionInvocationHandler<T>(this);
        LambdaCondition<T> lambdaCondition = (LambdaCondition<T>) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{LambdaCondition.class}, invocationHandler);
        return lambdaCondition;
    }

    @Override
    public Response<T> execute() {
        if(hasExecute){
            throw new IllegalArgumentException("该Condition已经执行过,不能再次执行!");
        }
        boolean addColumnAliasName = false;
        if(!queryOption.subQueryOptionList.isEmpty()){
            addColumnAliasName = true;
        }

        QueryContext queryContext = new QueryContext();
        queryContext.queryOption = queryOption;
        queryOption.quickFlow.startFlow(new ExecuteConditionCompositeBusiness())
                .putTemporaryData("queryContext", queryContext)
                .putTemporaryData("addColumnAliasName", addColumnAliasName)
                .putTemporaryData("addTableAliasName", true)
                .execute();
        hasExecute = true;

        Response response = new ResponseImpl(queryContext);
        return response;
    }

    @Override
    public Condition clone() {
        FlowContext flowContext = queryOption.quickFlow.startFlow(new CloneConditionFlow())
                .putCurrentCompositeFlowData("queryOption", queryOption)
                .execute();
        QueryOption cloneQueryOption = (QueryOption) flowContext.checkData("cloneQueryOption");
        return new ConditionImpl(cloneQueryOption);
    }

    @Override
    public DAO getDAO() {
        return queryOption.quickDAOConfig.dao;
    }

    /**
     * 添加in查询
     */
    private void addInQuery(String field, Object[] values, String in) {
        if (null == values || values.length == 0) {
            return;
        }
        StringBuilder builder = new StringBuilder();
        builder.append(" {} " + in + " (");
        for (int i = 0; i < values.length; i++) {
            builder.append("?,");
        }
        builder.deleteCharAt(builder.length() - 1);
        builder.append(")");
        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", field, builder.toString()));
        queryOption.queryFragmentOption.whereParameterList.addAll(Arrays.asList(values));
    }

    /**
     * 添加exist查询
     */
    private void addExistSubQuery(Condition subCondition, String exist) {
        queryOption.setConditionTableAliasName(subCondition);
        FlowContext flowContext = queryOption.quickFlow.startFlow(new GetFromConditionStatement())
                .putTemporaryData("fromCondition", subCondition)
                .execute();
        String fromConditionStatement = (String) flowContext.checkData("fromConditionStatement");
        List<Object> fromConditionParameters = (List<Object>) flowContext.getData("fromConditionParameters");

        queryOption.queryFragmentOption.whereList.add(new SQLFragmentEntry("and", null, exist + " (" + fromConditionStatement + ")"));
        queryOption.queryFragmentOption.whereParameterList.addAll(fromConditionParameters);
    }

}